package com.himiotech.core.project.web.system;

import com.himiotech.core.framework.helper.anno.Log;
import com.himiotech.core.framework.helper.constant.UserConstants;
import com.himiotech.core.framework.helper.enums.BusinessType;
import com.himiotech.core.framework.helper.model.SimpleDataTree;
import com.himiotech.core.framework.helper.model.XmSelectTree;
import com.himiotech.core.framework.helper.utils.AuthorizationUtils;
import com.himiotech.core.project.helper.utils.FontAwesomeUtils;
import com.himiotech.core.project.model.entity.Menu;
import com.himiotech.core.project.model.entity.role.Role;
import com.himiotech.core.project.service.IMenuService;
import com.himiotech.core.project.web.base.HimioBaseController;
import com.himiotech.core.project.web.base.model.HimioResult;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 菜单信息
 *
 * @author ruoyi
 * @author wuwenbin
 */
@Controller
@RequestMapping("/system/menu")
public class MenuController extends HimioBaseController {

    private static List<String> FONT_LIST = new ArrayList<>();

    @Autowired
    private IMenuService menuService;
    @Autowired
    private RequestMappingHandlerMapping requestMapping;

    @PostConstruct
    public void init() {
        FONT_LIST = FontAwesomeUtils.getAllFonts();
    }

    @RequiresPermissions("system:menu:view")
    @GetMapping()
    public String menu(Model model) {
        List<XmSelectTree> xmSelectTrees = menuService.menuTreeData();
        model.addAttribute("allMenu", xmSelectTrees);
        model.addAttribute("urlSet", getAllUrlsDefined());
        return "system/menu/menu";
    }

    @RequiresPermissions(value = {"system:menu:add", "system:menu:edit"}, logical = Logical.OR)
    @GetMapping("/font/list")
    public String fontList() {
        request.setAttribute("fonts", FONT_LIST);
        return "system/menu/fonts";
    }

    @RequiresPermissions("system:menu:list")
    @PostMapping("/list")
    @ResponseBody
    public HimioResult list(Menu menu) {
        return writeJsonLayuiTable(menuService.selectMenuList(menu));
    }

    /**
     * 删除菜单
     */
    @Log(title = "菜单管理", businessType = BusinessType.DELETE)
    @RequiresPermissions("system:menu:remove")
    @PostMapping("/remove/{menuId}")
    @ResponseBody
    public HimioResult remove(@PathVariable("menuId") Long menuId) {
        if (menuService.selectCountMenuByParentId(menuId) > 0) {
            return writeJsonErr("存在子菜单,不允许删除");
        }
        if (menuService.selectCountRoleMenuByMenuId(menuId) > 0) {
            return writeJsonErr("菜单已分配,不允许删除");
        }
        AuthorizationUtils.clearAllCachedAuthorizationInfo();
        return writeJson(menuService.deleteMenuById(menuId));
    }

    /**
     * 新增保存菜单
     */
    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
    @RequiresPermissions("system:menu:add")
    @PostMapping("/add")
    @ResponseBody
    public HimioResult addSave(@Validated Menu menu) {
        if (UserConstants.MENU_NAME_NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
            return writeJsonErr("新增菜单'" + menu.getMenuName() + "'失败，菜单名称已存在");
        }
        AuthorizationUtils.clearAllCachedAuthorizationInfo();
        return writeJson(menuService.save(menu));
    }

    /**
     * 修改保存菜单
     */
    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
    @RequiresPermissions("system:menu:edit")
    @PostMapping("/edit")
    @ResponseBody
    public HimioResult editSave(@Validated Menu menu) {
        if (UserConstants.MENU_NAME_NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
            return writeJsonErr("修改菜单'" + menu.getMenuName() + "'失败，菜单名称已存在");
        }
        AuthorizationUtils.clearAllCachedAuthorizationInfo();
        return writeJson(menuService.updateById(menu));
    }

    /**
     * 校验菜单名称
     */
    @PostMapping("/checkMenuNameUnique")
    @ResponseBody
    public String checkMenuNameUnique(Menu menu) {
        return menuService.checkMenuNameUnique(menu);
    }

    /**
     * 加载角色菜单列表树
     */
    @GetMapping("/roleMenuTreeData")
    @ResponseBody
    public List<SimpleDataTree<Menu>> roleMenuTreeData(Role role) {
        return menuService.roleMenuSimpleTreeData(role);
    }

    /**
     * 加载所有菜单列表树
     */
    @GetMapping("/menuTreeData")
    @ResponseBody
    public List<SimpleDataTree<Menu>> menuTreeData() {
        return menuService.menuSimpleTreeData();
    }

    private Set<String> getAllUrlsDefined() {
        Set<String> urlSet = new HashSet<>();
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods();
        handlerMethods.forEach((info, method) -> {
            if (!method.getMethod().isAnnotationPresent(ResponseBody.class)) {
                PatternsRequestCondition p = info.getPatternsCondition();
                urlSet.addAll(p.getPatterns());
            }
        });
        return urlSet;
    }
}